//============================================================================
// Name        : csiena
// Author      : Josh Lospinoso
// Copyright   : MIT License
// Description : Austere, limited implementation of the R package RSiena in
//				 C++. Used for fast maximum likelihood and method of moments
//				 estimation of stochastic actor oriented models (SAOMs)
//				 without any frills or user experience niceties.
//============================================================================

#ifndef CHAIN_H_
#define CHAIN_H_
#include "digraph.h"
#include "link.h"
#include "crimp.h"
#include "globals.h"
#include "evaluation.h"

#define MAX_PERMUTE

namespace csiena {

class Chain {
public:
	// Initializer methods
	Chain(int actors);
	Chain(const Chain &donorChain);
	virtual ~Chain();

	// Accessor methods
	int getActors();
	double getBetaScore(int k);
	double getBetaInformation(int a, int b);
	double getGammaScore(int k);
	double getGammaInformation(int a, int b);
	double getScore(int k);
	double getInformation(int a, int b);
	double getLogLikelihood();
	int getDiagonalElements();
	int getChainSize();
	int getLinkCount();
	int getCrimpCount();
	void setAlpha(double value);
	void incrementAlpha(double value);
	double getAlpha();
	double getAlphaScore();
	double getAlphaInformation();

	// Chain position methods
	void rewind();
	void fastForward();
	void setPosition(int position);
	void advanceChain();
	void retreatChain();

	// Link insertion/deletion methods
	void deleteCurrentElement();
	void insertLinkAfter(int i, int j);
	void insertCrimpAfter(Digraph* observedDigraph);
	void insertCrimpAfter(const char* fileName);
	void insertCrimpAfter();
	void insertSimulatedLinkAfter(MersenneTwister* r);
	void insertSimulatedCrimpAfter(MersenneTwister* r);

	// Utility methods
	void print();
	void printLinkedList();
	void clearChain();
	void resetX();
	void resetStart();
	void resetChain();

	// Chain evaluation methods
	void evaluateChain(int start, int stop);
	void evaluateChain();

	// MCMC Methods
	bool permute(MersenneTwister* r);
	bool insertDiagonal(MersenneTwister* r);
	bool deleteDiagonal(MersenneTwister* r);
	bool insertConsecutivelyCancelingPair(MersenneTwister* r);
	bool deleteConsecutivelyCancelingPair(MersenneTwister* r);
	bool insertEndCrimpElement(MersenneTwister* r);
	bool deleteEndCrimpElement(MersenneTwister* r);
	void permutedIntegers(int size, MersenneTwister* r, int* integers);
	void simulateStartingDigraph(int steps, MersenneTwister *r);
	bool drawProposal(MersenneTwister* r);

	// Ingredients used by MCMCMLE
	LinkEvaluation* linkEvaluationFunction;
	CrimpEvaluation* crimpEvaluationFunction;

	// The "startingDigraph" should be admitted as a dependent variable,
	// but until we figure out an appropriate proposal distribution,
	// it will be constant.
	Digraph* startingDigraph;
	Digraph* currentDigraph;
	ChainElement* currentElement;

private:
	// Private convenience methods
	void incrementBetaScore(int a, double value);
	void incrementBetaInformation(int a, int b, double value);
	void setBetaScore(int a, double value);
	void setBetaInformation(int a, int b, double value);
	void incrementGammaScore(int a, double value);
	void incrementGammaInformation(int a, int b, double value);
	void setGammaScore(int a, double value);
	void setGammaInformation(int a, int b, double value);
	void setLogLikelihood(double value);
	void incrementLogLikelihood(double value);
	void resetLikelihoodStatistics();

	double alpha;
	double logLikelihood;
	double* betaScore;
	double* betaInformation;
	double* gammaScore;
	double* gammaInformation;

	int currentElementIndex;
	int chainSize;
	int actors;
	int diagonalElements;
	int crimps;
	ChainElement* permuteProposal[PERMUTE_MAX];
};

}

#endif /* CHAIN_H_ */
